/*
*@author: Mr.xue 
*@date  : 2016/9/1
*/

// 默认的验证方式
var checkWay = { //函数自带的验证方式,通过在html的input元素上添加data-checkway属性来传入自定义验证方式,除此之外还可以在data-checkway属性上添加正则表达式

    defaultWay: function (input_value) {
        return "success";
    },
    select: function (input_value) {
        if (input_value == "0") return checkMess["select"];
        else return "success";
    },										//下拉框验证方式（比较特殊）本函数默认验证下拉未选择即默认值等于0的情况
    mobliephone: function (input_value) {
        if ((!/(^(13|14|15|17|18)\d{9}$)/.test(input_value))) return checkMess["mobliephone"];
        else return "success";
    }, 										//手机号码 验证方式
    telphone: function (input_value) {
        if ((!/^((\d{3,4}\-)|)\d{7,8}(|([-\u8f6c]{1}\d{1,5}))$/.test(input_value))) return checkMess["telphone"];
        else return "success";
    }, 										//固定电话 验证方式
    mobAndTel: function (input_value) {
        if ((!/((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)/.test(input_value))) return checkMess["mobAndTel"];
        else return "success";
    },
    username: function (input_value) {
        if ((!/^[\u4e00-\u9fff\w]{2,25}$/.test(input_value))) return checkMess["username"];
        else return "success";
    },										//用户名 验证方式
    realname: function (input_value) {
        if ((!/^[\u4e00-\u9fa5]*$/.test(input_value))) return checkMess["realname"];
        else return "success";
    },										//用户真实姓名 验证方式
    date: function (input_value) {
        if ((!/^(19|20)\d{2}-(1[0-2]|0?[1-9])-(0?[1-9]|[1-2][0-9]|3[0-1])$/.test(input_value))) return checkMess["data"];
        else return "success";
    }, 										//日期 验证方式
    companyname: function (input_value) {
        if ((!/^[\u4e00-\u9fff\w]{5,25}$/.test(input_value))) return checkMess["companyname"];
        else return "success";
    }, 										//公司名称 验证方式
    money: function (input_value) {
        if ((!/^\+?[1-9][0-9]*$/.test(input_value))) return checkMess["money"];
        else return "success";
    }, 										//资金 验证方式
    password: function (input_value) {
        if ((!/^[\@A-Za-z0-9\!\#\$\%\^\&\*\.\~]{6,18}$/.test(input_value))) return checkMess["password"];
        else return "success";
    }, 										//密码 验证方式
    passagain: function (input_value, input_dom) {
        var password_selector = $(input_dom).attr("data-confirm");
        if (password_selector == null) password_selector = $("input[data-checkway=password]");
        var password_Val = $(password_selector).val();
        var passAgain_Val = input_value;
        if (password_Val != "" && password_Val != null) {
            if (passAgain_Val == password_Val) return "success";
            else return "俩次密码填写不一致！";
        } else {
            return "密码不为空时才可以填写该项！";
        }
    },									 	 //二次确认密码验证方式
    banknum: function (input_value) {
        if ((!/\d{16}/g.test(input_value))) return checkMess["banknum"];
        else return "success";
    }, 										//银行卡号码 (简单)验证方式
    postalcode: function (input_value) {
        if ((!/^[0-9]\d{5}$/.test(input_value))) return checkMess["postalcode"];
        else return "success";
    }, 										//邮政编码 验证方式
    email: function (input_value) {
        if ((!/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(input_value))) return checkMess["email"];
        else return "success";
    }, 										//邮箱地址 验证方式
    smscode: function (input_value) {
        if ((!/^\d{6}$/.test(input_value))) return checkMess["smscode"];
        else return "success";
    },	  									//短信验证码 验证方式
    imgCode: function (value) {
        if (value.length != 4) {       //判断用户输入的验证码是否是4位有效字符
            return "验证码不正确！"
        } else {
            var message = "";
            $.ajax({
                async: false,
                cache: false, //关闭ajax缓存
                type: 'POST',
                url: '/control/kaptcha/anon/checkVerifyCode.do',// 请求的action路径
                data: {"captchaCode": value},//参数
                error: function () {// 请求失败处理函数
                    message = '可能是网络的原因，验证码验证失败，刷新一下页面试试看吧！';
                },
                success: function (data) { //请求成功的处理函数
                    var mess = $.parseJSON(data);
                    if (mess == true) {
                        message = "success";
                    } else {
                        message = "验证码不正确！";
                    }
                }
            });
            return message;
        }
    },
    //扩展的验证方式 身份证号码格式 //复杂的身份证号码验证
    cardId: function (value) {
        var cardId = value.toUpperCase(); //获取身份证值，并转化为大写。
        var length = cardId.length;


        if (!(/(^\d{17}([0-9]|X)$)/.test(cardId))) {
            return "输入的身份证号长度不对，或者号码不符合规定！号码末位可以为数字或X。";
        }

        //校验位按照ISO 7064:1983.MOD 11-2的规定生成，X可以认为是数字10。
        //下面分别分析出生日期和校验位

        var len, re;
        len = length;
        if (len == 18) {
            re = new RegExp(/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/);
            var arrSplit = cardId.match(re);
            //检查生日日期是否正确
            var dtmBirth = new Date(arrSplit[2] + "/" + arrSplit[3] + "/" + arrSplit[4]);
            var bGoodDay;
            bGoodDay = (dtmBirth.getFullYear() == Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3])) && (dtmBirth.getDate() == Number(arrSplit[4]));
            if (!bGoodDay) {
                return "输入的身份证号里出生日期不对！";
            } else {
                //检验18位身份证的校验码是否正确。
                //校验位按照ISO 7064:1983.MOD 11-2的规定生成，X可以认为是数字10。
                var valnum;
                var arrInt = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
                var arrCh = new Array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
                var nTemp = 0, i;
                for (i = 0; i < 17; i++) {
                    nTemp += cardId.substr(i, 1) * arrInt[i];

                }
                valnum = arrCh[nTemp % 11];
                if (valnum != cardId.substr(17, 1)) {
                    return "18位身份证的校验码不正确！应该为：" + valnum;
                } else {

                    return "success";

                }

            }
        }
    },

    //扩展的验证函数  银行卡号码 (复杂)验证方式
    bankLuhm: function (bankno2) {   //银行卡号码 (复杂)验证方式

        //Luhm校验规则：16位银行卡号（19位通用）:
        // 1.将未带校验位的 15（或18）位卡号从右依次编号 1 到 15（18），位于奇数位号上的数字乘以 2。
        // 2.将奇位乘积的个十位全部相加，再加上所有偶数位上的数字。
        // 3.将加法和加上校验位能被 10 整除。
        var bankno = Trim(bankno2, "g"); //去除银行卡中间的空格
        var length = bankno.length;

        if (length < 16 || length > 19) {
            var errorMsg = "银行卡号长度必须在16到19之间!";
            return "银行卡号长度必须在16到19之间!";
        }

        if (!/\d{4}/g.exec(bankno)) {

            return "银行卡号必须全为数字!";
        }
        //开头6位
        var strBin = "10,18,30,35,37,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,58,60,62,65,68,69,84,87,88,94,95,98,99";
        if (strBin.indexOf(bankno.substring(0, 2)) == -1) {
            return "银行卡号开头6位不符合规范!";
        }

        var lastNum = bankno.substr(bankno.length - 1, 1);//取出最后一位（与luhm进行比较）

        var first15Num = bankno.substr(0, bankno.length - 1);//前15或18位
        var newArr = new Array();
        for (var i = first15Num.length - 1; i > -1; i--) {    //前15或18位倒序存进数组
            newArr.push(first15Num.substr(i, 1));
        }
        var arrJiShu = new Array();  //奇数位*2的积 <9
        var arrJiShu2 = new Array(); //奇数位*2的积 >9

        var arrOuShu = new Array();  //偶数位数组
        for (var j = 0; j < newArr.length; j++) {
            if ((j + 1) % 2 == 1) {//奇数位
                if (parseInt(newArr[j]) * 2 < 9)
                    arrJiShu.push(parseInt(newArr[j]) * 2);
                else
                    arrJiShu2.push(parseInt(newArr[j]) * 2);
            } else //偶数位
                arrOuShu.push(newArr[j]);
        }

        var jishu_child1 = new Array();//奇数位*2 >9 的分割之后的数组个位数
        var jishu_child2 = new Array();//奇数位*2 >9 的分割之后的数组十位数
        for (var h = 0; h < arrJiShu2.length; h++) {
            jishu_child1.push(parseInt(arrJiShu2[h]) % 10);
            jishu_child2.push(parseInt(arrJiShu2[h]) / 10);
        }

        var sumJiShu = 0; //奇数位*2 < 9 的数组之和
        var sumOuShu = 0; //偶数位数组之和
        var sumJiShuChild1 = 0; //奇数位*2 >9 的分割之后的数组个位数之和
        var sumJiShuChild2 = 0; //奇数位*2 >9 的分割之后的数组十位数之和
        var sumTotal = 0;
        for (var m = 0; m < arrJiShu.length; m++) {
            sumJiShu = sumJiShu + parseInt(arrJiShu[m]);
        }

        for (var n = 0; n < arrOuShu.length; n++) {
            sumOuShu = sumOuShu + parseInt(arrOuShu[n]);
        }

        for (var p = 0; p < jishu_child1.length; p++) {
            sumJiShuChild1 = sumJiShuChild1 + parseInt(jishu_child1[p]);
            sumJiShuChild2 = sumJiShuChild2 + parseInt(jishu_child2[p]);
        }
        //计算总和
        sumTotal = parseInt(sumJiShu) + parseInt(sumOuShu) + parseInt(sumJiShuChild1) + parseInt(sumJiShuChild2);

        //计算Luhm值
        var k = parseInt(sumTotal) % 10 == 0 ? 10 : parseInt(sumTotal) % 10;
        var luhm = 10 - k;

        if (lastNum == luhm) {
            return "success";  //"Luhm验证通过!";
        } else {
            return "银行卡号必须符合Luhm校验!";
        }
    }
};

//函数自带的验证提示,你也可以在html的input元素上添加data-errmsg属性来自定义你的提示(这里的都是一些简单的验证函数的提示)
var checkMess = {
    select: "请选择！",
    mobliephone: "请填写格式正确的手机号码!",
    telphone: "请填写格式正确的固定电话号码！",
    mobAndTel: "请填写格式正确的联系电话号码，可以填写固定电话与手机号码！",
    username: "用户名由汉字，数字，英文大小写以及下划线_组成，最少2个，最多25个!",
    realname: "真实姓名为2-10个汉字字符!",
    date: "请填写格式正确的日期，日期格式例如：2016-12-12！",
    companyname: "公司名称最少5个字符，最多25个字符!",
    money: "注册资金为非负的正整数!",
    password: "密码由字母，数字以及【! # $ % ^ & * . ~】这些特殊字符组成，至少6个,最多18个!",
    banknum: "银行卡号必须全为数字!",
    postalcode: "邮政编码格式不正确，中国邮编格式为6位数字!",
    email: "请填写格式正确的邮箱地址!",
    smscode: "短信校验码格式错误!"
};

var checkUrl = {
    mobliephone: "/control/member/anon/checkMobilePhoneReg.do",
    username: "/control/member/anon/checkMemberNameReg.do",
    smscode: "/control/member/anon/verifySmsCode.do"
};
var checkData = {};
//默认参数（放在方法体外面是因为可预防该值多次实例化被改变）
var defaultOptions = {
    tipsSide: 1, 			//1,2,3,4 分别代表【上右下左】  [1,4]代表位置在1~4随机 例如：[2,3]代表位置在2~3随机
    tipsColor: '#FFF',  	//错误提示的文字颜色
    tipsBg: "red", 		    //错误提示的背景颜色
    tipsTime: 3, 			//错误提示自动消失秒数
    tipsX: 0, 			    //错误提示横向偏移px
    tipsY: 0, 			    //错误提示纵向偏移px
    tipsCount: "each", 		//“only,each,more”,only代表当前页面只能有一个tip，each代表每个input都能有一个tip，more代表当前页面不限制tip，新的添加 旧的也不关闭
    tipsMaxWidth: "130", 		//tip的最大显示宽度（px）
    tipsScroll: null, 		// 该参数接受选择器，定义的选择器的dom在滚动时将重新计算input距离窗口边界的值。在一些特殊的弹出层比较有用
    notEmpty: true, 		//是否开启非空验证（true表示验证组件的值不能为空，false表示可以为空。默认true）
    event: "change", 		//默认的表单校验触发事件,你可以通过在html的input元素上添加data-event属性来传入自定义事件
    inputBox: "input",		//默认所有input都触发,你可以传入你自己的选择器
    parentBox: null,		//默认的input的父元素（通过null占位下面代码会进行判断）,你也可以传入自己的选择器来指定父元素
    btnSubmit: null,  		//表单提交按钮（选择器）
    btnReset: null,  		//表单重置按钮（选择器）
    resetCall: null,		//表单重置后的回调函数，有时你可能需要重置表单后还做些什么
    Enter: true, 		    //是否开启键盘回车触发checker提交
    btnSendSms: null, 		//发送短信验证码的按钮（选择器）
    smsUrl: '/control/sms/anon/sendSms.do',//默认的发送短信的接口（路径）
    smsData: {}, 			//该字段用于发送短信验证码时的参数，可以用来补充参数。
    dyncLdForm: false, 		//是否动态的加载Form表单，true代表是，用于解决form是后插入页面的元素 选不中的问题
    //action  : $thisForm.attr("action"),  		//默认的表单提交路径
    //method  : $thisForm.attr("method"), 		//默认的表单提交方式
    async: true, 		//表单提交时使用异步或者同步方式，true异步，false同步
    data: {}, 			//该字段用于设置表单提交时，有些参数无法序列化，从而手动的将这些参数添加到发送的数据中。例如一个div中的text()就无法序列化这时你可以构造一个对象{divname:divtext}放到这里
    dataType: "object" 	//表单提交的数据格式 "object"代表对象格式，"string"代表字符串格式
    //callback 	: errorCallback //表单提交成功的回调函数，注意只有请求成功才有回调函数，回调函数自己定义
};


function checker2(formbox, options) {
    //定义变量缓存当前表单
    var $thisForm = $(formbox);
    //定义变量缓存当前表单的验证对象
    var $thisChecker = this;

    var formOptions = {
        action: $thisForm.attr("action"), //默认的表单提交路径
        method: $thisForm.attr("method"), //默认的表单提交方式
        callback: errorCallback 		  //表单提交成功的回调函数，注意只有请求成功才有回调函数，回调函数自己定义
    };
    var checkerOptions = $.extend({}, defaultOptions, formOptions, options || {});
    //--------------- 公共方法 start --------------//

    //设置参数方法,可对当前校验对象的参数进行重新设置
    this.setOptions = function (tsetOptions, tsetFormbox) {
        var strTformbox = tsetFormbox || $thisForm;
        var tformbox = $(strTformbox);
        var newcheckerOptions = $.extend({}, checkerOptions, tsetOptions);
        var newSelectorString = initSelector(tformbox, newcheckerOptions);
        //移除旧的验证组件事件
        removeEventListening(checkerOptions, $thisForm, selectorString);
        //注册新的验证组件事件
        addEventListening(newcheckerOptions, tformbox, newSelectorString);
        $thisForm = tformbox;
        checkerOptions = newcheckerOptions;
        selectorString = newSelectorString;
        return this;
    };
    //获取当前校验对象参数
    this.getOptions = function (options) {
        checkerOptions.formSelector = $thisForm.selector;
        return checkerOptions;
    };
    //设置校验方式
    this.setCheckway = function (settingObj) {
        checkWay = $.extend({}, checkWay, settingObj);
        return this;
    };
    //设置检验提示
    this.setCheckMess = function (settingObj) {
        checkMess = $.extend({}, checkMess, settingObj);
        return this;
    };
    //设置检验远程路径
    this.setCheckUrl = function (settingObj) {
        checkUrl = $.extend({}, checkUrl, settingObj);
        return this;
    };
    //设置检验的数据
    this.setCheckData = function (settingObj) {
        checkData = $.extend({}, checkData, settingObj);
        return this;
    };
    //设置表单提交的数据
    this.setFormData = function (settingObj) {
        //checkerOptions.data  = settingObj;
        checkerOptions.data = $.extend({}, checkerOptions.data, settingObj);
        return this;
    };
    //设置表单中发生短信验证码提交的数据
    this.setSmsData = function (settingObj) {
        checkerOptions.smsData = settingObj;
        return this;
    };
    //触发表单验证的错误条数
    this.triggers = function () {	  //经代码优化后测试得出，392个输入组件dom找的速度大概0.2秒，js 事件响应0.55秒，定位提示2.9秒
        $thisForm.find(checkerOptions.inputBox).not("[resultsof='s'],[data-nocheck]").trigger(checkerOptions.event); //集中触发事件,触发错误条数 *find()函数速度较快一些
        return ($thisForm.find("[resultsof='e']").length <= 0);
    };
    //重置表单
    this.resets = function () {
        resetForm2($thisForm);
        return this;//($thisForm.find("[resultsof]").length<=0);
    };
    //卸载checker2
    this.uninst = function () {
        resetForm2($thisForm);
        removeEventListening(checkerOptions, $thisForm, selectorString);
        return this;
    };
    //---------------公共方法 end --------------//

//##########################################   构造checker验证所需要的组件   ##################################################
    checker2WorkInfo();//checker2工作信息提示
    //事件代理对象 																			  #
    var eventAgent = $(document);
    //错误样式
    var tips_box_onError = "border:1px solid #f30a04;box-shadow:0px 0px 9px #fb0000;border-radius:3px;";
    //成功样式
    var tips_box_onSuccess = "border:1px solid #0fb112;box-shadow:0px 0px 9px #36af38;border-radius:3px;";
    var _RegExp = new RegExp(/^(border:1px|border: 1px)(.|\n)*(border-radius:3px;|border-radius: 3px;)/gi); //非ie清除验证样式正则
    if (!!window.ActiveXObject || "ActiveXObject" in window) { 		//判断ie浏览器
        _RegExp = /^(border-radius:3px|border-radius: 3px).*(#fb0000;|#36af38;)/gi;
    }
    //构造选择器
    var selectorString = initSelector($thisForm, checkerOptions);
    //先移除事件，预防多次实例checker2导致事件被多次重复注册引起冲突
    removeEventListening(checkerOptions, $thisForm, selectorString);
    //添加checker 的验证事件
    addEventListening(checkerOptions, $thisForm, selectorString);
//																															   #
//##############################################################################################################################
    //----------------私有方法
    //构造多选择器函数
    function initSelector(from, options) {
        var selectorArray = options.inputBox.split(',');
        var selectorString = "";
        for (var i = 0; i < selectorArray.length; i++) {
            selectorString += "," + from.selector + " " + selectorArray[i] + ":not([data-nocheck])";
        }
        ;
        return selectorString.substr(1);
    };

    //错误信息提示样式及结果
    function errmsgStyle(inputbox, errmsg) {
        var thisBoxStyle = inputbox.getAttribute("style") == null ? "" : inputbox.getAttribute("style");
        thisBoxStyle = thisBoxStyle.replace(_RegExp, "");
        //重新给style属性赋值。
        inputbox.setAttribute("style", tips_box_onError + thisBoxStyle);
        //给input赋予校验结果，s为成功，e为失败，提交时只重复检验失败的input直到成功。
        inputbox.setAttribute("resultsof", "e");
        $(inputbox).tips({
            side: checkerOptions.tipsSide,  	//1,2,3,4 分别代表 上右下左
            msg: errmsg,						//tips的文本内容
            color: checkerOptions.tipsColor,	//文字颜色，默认为白色
            bg: checkerOptions.tipsBg,			//背景色，默认为红色
            time: checkerOptions.tipsTime,		//默认为2 自动关闭时间 单位为秒 0为不关闭 （点击提示也可以关闭）
            x: checkerOptions.tipsX,			// 默认为0 横向偏移 正数向右偏移 负数向左偏移
            y: checkerOptions.tipsY, 			// 默认为0 纵向偏移 正数向下偏移 负数向上偏移
            tipsCount: checkerOptions.tipsCount,
            maxWidth: checkerOptions.tipsMaxWidth,
            scroll: checkerOptions.tipsScroll
        });
    };

    //成功样式提示信息及结果
    function sucmsgStyle(inputbox, sucmsg) {
        //获取当前输入组件的style属性值
        var thisBoxStyle = inputbox.getAttribute("style") == null ? "" : inputbox.getAttribute("style");
        thisBoxStyle = thisBoxStyle.replace(_RegExp, "");
        //重新给style属性赋值(验证提示样式)。
        inputbox.setAttribute("style", tips_box_onSuccess + thisBoxStyle);
        //给input赋予校验结果，s为成功，e为失败，提交时只重复检验失败的input直到成功。
        inputbox.setAttribute("resultsof", "s");
        //清除错误提示的样式
        $("div[thistipNo='" + inputbox.getAttribute("tipNo") + "']").remove();
    };

    //checker2工作信息提示
    function checker2WorkInfo() {

        if (!!window.ActiveXObject || "ActiveXObject" in window) {
            if ($thisForm.length == 1) {
                console.info("checker2 在您的名称为：" + $thisForm.selector + " 的表单下运行正常 O(∩_∩)O ！");
            } else if ($thisForm.length > 1) {
                console.warn("checker2 在您的名称为：" + $thisForm.selector + " 的表单下努力奔跑中‘（*^﹏^*）′ ！但您在一个实例中选择了多个表单，如您使用checker2为您内置的表单提交函数，可能会发生一些未知的错误。");
            } else if ($thisForm.length < 1 && !checkerOptions.dyncLdForm) {
                console.error("checker2 运行发生错误 (x___x) ，您的名称为" + $thisForm.selector + " 的表单不存在于当前DOM！");
            }
            ;
            return;
        }
        ;
        if ($thisForm.length == 1) {
            console.info("%c checker2 在您的名称为：" + $thisForm.selector + " 的表单下运行正常 O(∩_∩)O ！", "color:#0421EF");
        } else if ($thisForm.length > 1) {
            console.warn("%c checker2 在您的名称为：" + $thisForm.selector + " 的表单下努力奔跑中‘（*^﹏^*）′ ！但您在一个实例中选择了多个表单，如您使用checker2为您内置的表单提交函数，可能会发生一些未知的错误。", "color:#038035");
        } else if ($thisForm.length < 1 && !checkerOptions.dyncLdForm) {
            console.error("%c checker2 运行发生错误 (x___x) ，您的名称为" + $thisForm.selector + " 的表单不存在于当前DOM！", "color:red");
        }
        ;
    };

    //input的远程验证ajax
    function ajaxCheck(checkData, checkUrl, inputBoxID, parentBoxID, ajaxjieguo) {

        $.ajax({
            cache: false, //禁止ajax缓存
            type: 'POST',
            url: checkUrl,// 请求的action路径
            data: checkData,//发送参数
            error: function (data) {	// 请求失败处理函数
                alert("该字段在服务端验证失败，请检查您的网络或者验证路径！");
            },
            success: function (data) { //请求成功回调函数
                var succMesssge = $.parseJSON(data);
                succMesssge = succMesssge.toString();
                if (succMesssge == ajaxjieguo) { //失败时走的函数
                    var errorMsg = (inputBoxID.getAttribute("data-ajaxmsg") == null ? "您填写的内容与服务器端的存储内容不符！" : inputBoxID.getAttribute("data-ajaxmsg"));
                    errmsgStyle(inputBoxID, errorMsg);
                } else {
                    sucmsgStyle(inputBoxID);
                }
            }
        });
    };

    /*
    @表单的提交ajax
    *url 		: ajax发送请求的路径
    *data 	: ajax发送请求时携带的参数
    *ajaxtype : ajax的请求方式 post get
    *ajaxasync: ajax的同步与异步
    *callback : ajax请求成功的回调函数
    */
    function subformAjax(url, data, ajaxtype, ajaxasync, callback) {
        //将ajax发送的参数补全
        data = $.extend(data, checkerOptions.data);
        //构造json对象字符串
        var data2 = JSON.stringify(data);
        //设置字符集
        var conType = "application/json;charset=UTF-8";
        if (checkerOptions.dataType == "string") { //判断当前表单数据需要发送为 a&b&c 的形式
            //反序列化对象 a&b&c
            data2 = $.param(data);
            //设置字符集
            conType = "application/x-www-form-urlencoded";
        }
        ;
        checkerOptions.data = {};
        $.ajax({
            async: ajaxasync,
            cache: false, //禁止ajax缓存
            type: ajaxtype,
            url: url, // 请求的action路径
            data: data2,
            dataType: "json",
            contentType: conType,
            error: function (data) {  // 请求失败处理函数
                callback("error");
            },
            success: function (data) {
                callback(data);
            }
        });
    };

    //表单提交函数验证并且发送表单对象到服务器（调用subformAjax()）
    function subform(btnSubmit) {
        if ($thisChecker.triggers()) { //判断错误条数
            var ajaxtype = (checkerOptions.method == null ? 'post' : checkerOptions.method); //获取页面表单元素的提交方式，没有设置默认"post"
            if (checkerOptions.action != null) { //判断验证表单的提交路径 ，错误时提示错误信息
                var sdataobj = paramString2object($thisForm); //序列表单并构造对象
                subformAjax(checkerOptions.action, sdataobj, ajaxtype, checkerOptions.async, checkerOptions.callback); //提交表单函数
            } else {
                layer.msg("您的表单没有 有效地址！", {icon: 5, time: 2000, offset: '45%'});
            }
            ;
        } else {
            throw new Error('您的表单中还有未验证通过的项，可能是还有隐藏的输入组件，请使用 属性 inputBox 排除。');
            //window.parent.layer.alert('请正确填写各项信息后，<br>再点击『'+(btnSubmit!=null?(btnSubmit.text()!=""?btnSubmit.text():btnSubmit.val()):"提交")+'』！', {icon: 2,offset: '40%'});
        }
        ;
    };

    //错误的回调函数时走这个函数进行提示
    function errorCallback(data) {
        if (data != "error") {
            console.log("您的值已成功从服务端" + checkerOptions.method + "到，值为 ：" + data);
            alert("声明：请求成功！<br>但您没有指定表单提交成功的回调函数！");
        } else {
            alert("声明：ajax已成功与服务器建立链接！<br>但您的表单参数可能与服务器要求不符合，<br>请检查！");
        }
        ;
    };

    /*回车敲击触发事件，调用例如：_enterEvent(memberLogin);*/
    function _enterEvent2(key_back) {
        key_back = new key_back();
        document.onkeyup = function (event) {
            var e = event || window.event || arguments.callee.caller.arguments[0];
            if (e && e.keyCode == 13) {
                key_back.enterup();
            }
            ;
        };
    };


    //发送验证码函数
    /* sendData: 要发送的手机号码
    * sendUrl：请求的地址
    * messbtn：发送验证码按钮的id 或者 class ，（jquery属性选择）
    调用本函数，例如：
        $('#messbtn').click(function(){
            sendCode2({'mobile':$("#updatePhone").val()},'/control/sms/anon/sendSms.do','#messbtn');
        });
    函数的ajax返回值为，字符串 "success","error"
    */
    function sendCode2(sendData, sendUrl, messbtn) {

        $.ajax({
            cache: false, //禁止ajax缓存
            type: 'POST',
            url: sendUrl,// 请求的action路径
            data: sendData,//发送参数
            error: function (data) {	// 请求失败处理函数
                alert("可能是网络的原因,数据请求失败");
            },
            success: function (data) {//请求成功回调函数
                var succMesssge = $.parseJSON(data);
                if (succMesssge == "success") {
                    settime2(messbtn);
                }
            }
        });
    };

    //验证码倒计时60秒
    function settime2(messbtn) {
        var countdown = 60; //验证码倒计时时间为60秒
        var sendtimer = setInterval(function () {
            countdown -= 1;
            if (countdown > 0) {
                $(messbtn).attr("disabled", "true");
                $(messbtn).text("重新发送(" + countdown + ")" + "秒");
                return;
            } else {
                clearInterval(sendtimer);
                $(messbtn).text("免费获取校验码");
                $(messbtn).removeAttr("disabled");
            }
            ;
        }, 1000);
    };

    //表单重置
    //formBoxID:需要重置的表单属性选择器，例如"#id",".class","[name='name']" 等等
    function resetForm2(formBoxID) {
        var inputbox = $(selectorString);
        inputbox.removeAttr("resultsof");  			//移除表单内的验证结果
        $(formBoxID)[0].reset();  					//重置表单填充的数据

        inputbox.each(function (index, domEle) {  	//重置表单提示的成功与失败的样式
            var old_style = $(domEle).attr("style") == null ? "" : $(domEle).attr("style");
            $(domEle).attr("style", old_style.replace(_RegExp, ""));
        });
        $("[thistipno]").remove();//重置表单验证结果（样式）
        if (checkerOptions.resetCall != null) {
            checkerOptions.resetCall();//重置完毕后的回调函数。
        }
    };

    /*
    表单序列化，字符串转对象格式。
    serializedParams格式为"key1=value1&key2=value2".
    也支持'key.sonkey=value'
    调用例如：var member2 = paramString2obj($("#registerForm")); //转化表单对象
     */
    function paramString2object(formBox) {
        var obj = {};
        var serializedParams = formBox.serialize();

        function evalThem(str) {
            var strAry = new Array();
            strAry = str.split("=");
            //使用decodeURIComponent解析uri 组件编码
            for (var i = 0; i < strAry.length; i++) {
                strAry[i] = decodeURIComponent(strAry[i]);
            }
            ;
            var attributeName = strAry[0];
            var attributeValue = strAry[1].trim();
            //如果值中包含"="符号，需要合并值
            if (strAry.length > 2) {
                for (var i = 2; i < strAry.length; i++) {
                    attributeValue += "=" + strAry[i].trim();
                }
                ;
            }
            ;
            if (!attributeValue) {
                return;
            }
            ;
            var attriNames = attributeName.split("."),
                curObj = obj;
            for (var i = 0; i < (attriNames.length - 1); i++) {
                curObj[attriNames[i]] ? "" : (curObj[attriNames[i]] = {});
                curObj = curObj[attriNames[i]];
            }
            ;
            //使用赋值方式obj[attributeName] = attributeValue.trim();替换
            //eval("obj."+attributeName+"=\""+attributeValue.trim()+"\";");
            //解决值attributeValue中包含单引号、双引号时无法处理的问题
            //这里可能存在一个种情况：多个checkbox同一个name的时候需要使用","来分割
            curObj[attriNames[i]] = curObj[attriNames[i]] ?
                (curObj[attriNames[i]] + "," + attributeValue.trim()) :
                attributeValue.trim();
        };
        if (serializedParams != "") {
            var properties = serializedParams.split("&");
            for (var i = 0; i < properties.length; i++) {
                //处理每一个键值对
                evalThem(properties[i]);
            }
            ;
        }
        ;
        return obj;
    };
    //----------------私有方法 end

    //-----------------为dom注册事件
    //触发input等可输入控件的事件，校验表单内容
    function checkerEvent() {
        // 定义变量记录this,缓存以尽可能的提高访问速度
        var _this = this;
        var $parent = {};   //(checkerOptions.parentBox==null?$this.parent():$this.parents(checkerOptions.parentBox));
        // 获取填入input的值,并去掉首尾的空格
        var inputval = _this.value.replace(/(^\s+)|(\s+$)/g, "");
        // 获取页面上的验证方式
        var checkwayHtml = _this.getAttribute("data-checkway");
        if (checkwayHtml == null) {
            checkwayHtml = "defaultWay"
        }
        // 构造检查方式,并接受返回的错误提示信息
        var checkerway = checkWay[checkwayHtml](inputval,_this);
        // 获取input允许输入的最大长度
        var checkMaxlen = parseInt(_this.getAttribute("data-maxlen"));
        if (isNaN(checkMaxlen)) checkMaxlen = 99999;
        // 获取input允许输入的最小长度
        var checkMinlen = parseInt(_this.getAttribute("data-minlen"));
        if (isNaN(checkMinlen)) checkMinlen = 0;
        //if (!checkerOptions.notEmpty)  checkMinlen=0; //不开启非空判断时，字符长度设为最小0 ，（暂保留）
        var checkSucMess = _this.getAttribute("data-sucmsg");
        if (checkSucMess == null) checkSucMess = " ";
        // 获取页面上input值为空时的提示
        var checkNullMess = _this.getAttribute("data-nullmsg");
        // 页面提示为空或未定义时,提示默认值
        if (checkNullMess == null) checkNullMess = "该字段不能为空!";
        // 获取页面上的验证失败提示
        var checkErrMess = _this.getAttribute("data-errmsg");
        // 页面提示为空或未定义时,提示默认值
        if (checkErrMess == null) checkErrMess = checkerway;
        // 获取页面上input值为空时的提示
        var checkErrlenMess = _this.getAttribute("data-lenmsg");
        if (checkErrlenMess == null) checkErrlenMess = "字符长度不符合要求，最大" + checkMaxlen + "位，最小" + (checkMinlen != 0 ? checkMinlen : 1) + "位！";
        // 获取页面上的ajax url与传参
        var checkAjaxurl = _this.getAttribute("data-ajaxurl");

        if (inputval == "" && checkerOptions.notEmpty == true) {
            var errorMsg = checkNullMess;
            errmsgStyle(_this, errorMsg);
            return;
        } else if (checkerway != "success") {
            var errorMsg = checkErrMess;
            errmsgStyle(_this, errorMsg);
            return;
        } else if (inputval.length < checkMinlen || inputval.length > checkMaxlen) {
            var errorMsg = checkErrlenMess;
            errmsgStyle(_this, errorMsg);
            return;
        } else {
            if (checkAjaxurl != null) {
                var checkDataObj = new Object();
                if (checkAjaxurl.indexOf("?") > -1) { //判断当前input的data-ajaxurl属性值是否包含? ,包含则将?前解析为url，?后解析为参数
                    var url = (checkAjaxurl.substr(0, checkAjaxurl.indexOf("?")));
                    var checkData = (checkAjaxurl.substring(checkAjaxurl.indexOf("?") + 1));
                    //构造ajax要发送的参数
                    checkDataObj[checkData] = inputval;
                    ajaxCheck(checkDataObj, url, _this, $parent, _this.getAttribute("data-ajax-result"));
                    return;
                }
                ;
                //调用new checker2().setCheckUrl()设置了ajax检查路径与发送参数后走这里
                ajaxCheck(checkData[checkAjaxurl], checkUrl[checkAjaxurl], _this, $parent, _this.getAttribute("data-ajax-result"));
                //window[callback](url);  //解析页面input的data-ajaxurl属性当做回调函数执行
                return;
            }
            ;
            sucmsgStyle(_this, checkSucMess);
        }
        ;
    };

    function sendSmsevent(event) {
        //获取该按钮上注册的input对象
        var sendInput = $(this).attr("data-smsinput");
        //如果没指定则默认找到验证方式为手机号码的input
        if (sendInput == null) sendInput = $thisForm.find("[data-checkway=mobliephone]");
        //缓存发送短信验证码的输入组件
        var sendInputDom = $(sendInput);
        //获取按钮上的短信验证发送时的键
        var sendDataKey = $(this).attr("data-smskey");
        //获取发送短信的键与值
        var sendData = $.extend({}, checkerOptions.smsData);
        if (sendDataKey != null) {  //如果dom上指定的键不为空 重新构造发送短信的参数键值
            var setObj = new Object();
            setObj[sendDataKey] = sendInputDom.val() || sendInputDom.text();
            sendData = $.extend({}, checkerOptions.smsData, setObj);
        }
        ;
        //获取发送短信的路径
        var sendDataUrl = checkerOptions.smsUrl;
        //获取dom上指定的短信路径
        var sendDataUrl_dom = $(this).attr("data-smsurl");
        if (sendDataUrl_dom != null) { //dom上指定的路径不为空时 ，以dom上指定的优先
            sendDataUrl = sendDataUrl_dom;
        }
        ;
        //sendInputDom.trigger("change");	//触发短信输入组件的change事件,有时输入框的值是预加载好的所以有必要change
        if (sendInputDom.attr("resultsof") == "s") { 	//判断没有报错条数是发送短信，有则提示重新填写
            //触发发送后清空指定的发送参数
            checkerOptions.smsData = {};
            sendCode2(sendData, sendDataUrl, $(this));
        } else {
            layer.msg('请正确填写手机号码后，再发送校验码！', {icon: 2, time: 2000, offset: '45%'});
        }
        ;
    };

    function resetFormEvent() {
        resetForm2($thisForm);
    };

    function dyloadFromEvent() {
        $thisForm = $($thisForm.selector);
    };

    function submitFormEvent(event) {
        subform(this);
    };

    //addEventListening 注册checker2验证所有需要的事件
    function addEventListening(newcheckerOptions, newForm, newSelectorString) {
        //表单输入组件的事件注册（很重要！！！）
        eventAgent.on(newcheckerOptions.event, newSelectorString, checkerEvent);

        //是否动态的加载Form表单，true代表是，用于解决form是后插入表单的元素选不中的问题
        if (newcheckerOptions.dyncLdForm == true) {
            eventAgent.on("mouseenter", newForm.selector, dyloadFromEvent);
        }
        ;
        //表单中发送短信验证码按钮的事件
        if (newcheckerOptions.btnSendSms != null) {
            //为btnSendSms绑定 mouseup 事件，并为其传入附加数据data
            eventAgent.on("mouseup", newForm.selector + " " + newcheckerOptions.btnSendSms, sendSmsevent);
        }
        ;
        /*@表单的提交与重置*/
        //表单重置按钮事件
        if (newcheckerOptions.btnReset != null) {
            eventAgent.on("mousedown", newForm.selector + " " + newcheckerOptions.btnReset, resetFormEvent);
        }
        ;
        //表单提交按钮鼠标事件
        if (newcheckerOptions.btnSubmit != null) {
            //为btnSubmit绑定 click 事件，并为其传入附加数据data
            eventAgent.on("click", newForm.selector + " " + newcheckerOptions.btnSubmit, submitFormEvent);

            if (newcheckerOptions.Enter) {  //开启回车提交
                //每个实例checker2 的表单做一个标记，预防一个页面显示多表单回车冲突
                newForm.attr("checker2", "working-now");
                //为每个实例每个实例checker2 的表单提交按钮做一个标记，用来回车提交数据
                $(newcheckerOptions.btnSubmit).attr("checker2Enter", "working-now");
                _enterEvent2(function () {
                    this.enterup = function () {
                        var checker2EnterForm = $("form[checker2]:visible");
                        var checker2Enter = checker2EnterForm.find("[checker2Enter]");
                        if (checker2EnterForm.length <= 1) { //判断当前页面中有可见的表单数量，如果多个表单禁用回车提交
                            checker2Enter.click();
                        }
                        ;
                    };
                });
            }
            ;
        }
        ;

    };

    function removeEventListening(oldcheckerOptions, oldForm, oldSelectorString) {
        //统一关闭事件，可防止事件多次注册引起冲突
        eventAgent.off(oldcheckerOptions.event, oldSelectorString, checkerEvent)
            .off("mouseenter", oldForm.selector, dyloadFromEvent)
            .off("mouseup", oldForm.selector + " " + oldcheckerOptions.btnSendSms, sendSmsevent)
            .off("mousedown", oldForm.selector + " " + oldcheckerOptions.btnReset, resetFormEvent)
            .off("click", oldForm.selector + " " + oldcheckerOptions.btnSubmit, submitFormEvent);
        //移除回车提交的触发
        $(oldcheckerOptions.btnSubmit).removeAttr("checker2Enter");
    };
    //-----------------为dom注册事件 end
};

/*
去除字符串中的空格函数，调用例如：var bankno = $(inputBoxID).val();  var bankno2=Trim(bankno,"g");
功能: 1)去除字符串前后所有空格
      2)去除字符串中所有空格(包括中间空格,需要设置第2个参数为:"g")
*/
function Trim(str, is_global) {
    var result;
    result = str.replace(/(^\s+)|(\s+$)/g, "");
    if (is_global.toLowerCase() == "g")
        result = result.replace(/\s/g, "");
    return result;
}